﻿using System;
using UnityEngine;

public class CCDIKSolver : MonoBehaviour
{
	public Transform target;
	public int iterations;
	public float controll_weight;
	public Transform[] chains;
	public bool drawRay;
	public float minDelta;
	public bool useLeg;
	public Quaternion[] lastFrameQ;
	public float lastFrameWeight = 0.9f;
	public void Solve()
	{
		if (this.useLeg)
		{
			this.SolveLeg();
			return;
		}
		this.SolveNormal();
	}

	public void SolveLeg()
	{
		if (this.lastFrameQ != null)
		{
			for (int i = 0; i < this.chains.Length; i++)
			{
				Quaternion localRotation = Quaternion.Slerp(this.chains[i].localRotation, this.lastFrameQ[i], this.lastFrameWeight);
				this.chains[i].localRotation = localRotation;
			}
		}
		else
		{
			this.lastFrameQ = new Quaternion[this.chains.Length];
		}
		float magnitude = (base.transform.position - this.chains[1].position).magnitude;
		float magnitude2 = (this.chains[0].position - this.chains[1].position).magnitude;
		float magnitude3 = (this.target.position - this.chains[1].position).magnitude;
		float num = magnitude2 + magnitude3;
		float num2 = -0.5f;
		int j = 0;
		int num3 = this.iterations;
		while (j < num3)
		{
			int k = 0;
			int num4 = this.chains.Length;
			while (k < num4)
			{
				Transform transform = this.chains[k];
				Vector3 position = transform.position;
				Vector3 vector = this.target.position - position;
				Vector3 vector2 = base.transform.position - position;
				if (this.drawRay)
				{
					Debug.DrawRay(position, vector, Color.green);
					Debug.DrawRay(position, vector2, Color.red);
				}
				float sqrMagnitude = vector.sqrMagnitude;
				float sqrMagnitude2 = vector2.sqrMagnitude;
				vector = vector.normalized;
				vector2 = vector2.normalized;
				float num5 = Mathf.Acos(Vector3.Dot(vector, vector2));
				Vector3 normalized = Vector3.Cross(vector, vector2).normalized;
				if (!float.IsNaN(num5) && num5 != 0f)
				{
					goto IL_23A;
				}
				if (k == 1 && this.chains[0].localEulerAngles.x == 0f && magnitude >= num)
				{
					this.StoreLastQ();
					return;
				}
				if (k == 1 && this.chains[0].localEulerAngles.x == 0f && sqrMagnitude2 < sqrMagnitude)
				{
					normalized = new Vector3(1f, 0f, 0f);
					num5 = num2;
					goto IL_23A;
				}
				IL_22F:
				k++;
				continue;
				IL_23A:
				float num6 = 4f * this.controll_weight * (float)(k + 1);
				if (num5 > num6)
				{
					num5 = num6;
				}
				if (num5 < -num6)
				{
					num5 = -num6;
				}
				num5 *= 57.29578f;
				if (float.IsNaN(normalized.x) || float.IsNaN(normalized.y) || float.IsNaN(normalized.z))
				{
					goto IL_22F;
				}
				Quaternion quaternion = Quaternion.AngleAxis(num5, normalized);
				transform.rotation = quaternion * transform.rotation;
				this.limitter(transform);
				if (this.minDelta != 0f && (this.target.position - base.transform.position).sqrMagnitude < this.minDelta)
				{
					this.StoreLastQ();
					return;
				}
				goto IL_22F;
			}
			j++;
		}
		this.StoreLastQ();
	}

	private void StoreLastQ()
	{
		for (int i = 0; i < this.chains.Length; i++)
		{
			this.lastFrameQ[i] = this.chains[i].localRotation;
		}
	}
	public void SolveNormal()
	{
		if (this.lastFrameQ != null)
		{
			for (int i = 0; i < this.chains.Length; i++)
			{
				Quaternion localRotation = Quaternion.Slerp(this.chains[i].localRotation, this.lastFrameQ[i], this.lastFrameWeight);
				this.chains[i].localRotation = localRotation;
			}
		}
		else
		{
			this.lastFrameQ = new Quaternion[this.chains.Length];
		}
		int j = 0;
		int num = this.iterations;
		while (j < num)
		{
			int k = 0;
			int num2 = this.chains.Length;
			while (k < num2)
			{
				Transform transform = this.chains[k];
				Vector3 position = transform.position;
				Vector3 vector = this.target.position - position;
				Vector3 vector2 = base.transform.position - position;
				if (this.drawRay)
				{
					Debug.DrawRay(position, vector, Color.green);
					Debug.DrawRay(position, vector2, Color.red);
				}
				vector = vector.normalized;
				vector2 = vector2.normalized;
				float num3 = Mathf.Acos(Vector3.Dot(vector, vector2));
				if (!float.IsNaN(num3))
				{
					float num4 = 4f * this.controll_weight * (float)(k + 1);
					if (num3 > num4)
					{
						num3 = num4;
					}
					if (num3 < -num4)
					{
						num3 = -num4;
					}
					num3 *= 57.29578f;
					Vector3 normalized = Vector3.Cross(vector, vector2).normalized;
					if (!float.IsNaN(normalized.x) && !float.IsNaN(normalized.y) && !float.IsNaN(normalized.z))
					{
						Quaternion quaternion = Quaternion.AngleAxis(num3, normalized);
						transform.rotation = quaternion * transform.rotation;
						this.limitter(transform);
						if (this.minDelta != 0f && (this.target.position - base.transform.position).sqrMagnitude < this.minDelta)
						{
							for (int l = 0; l < this.chains.Length; l++)
							{
								this.lastFrameQ[l] = this.chains[l].localRotation;
							}
							return;
						}
					}
				}
				k++;
			}
			j++;
		}
		for (int m = 0; m < this.chains.Length; m++)
		{
			this.lastFrameQ[m] = this.chains[m].localRotation;
		}
	}
	private void limitter(Transform bone)
	{
		if (bone.name.Contains("足首") || bone.name.Contains("_J_Foot01_"))
		{
			Vector3 localEulerAngles = bone.localEulerAngles;
			localEulerAngles.z = 0f;
			bone.localRotation = Quaternion.Euler(localEulerAngles);
			return;
		}
		if (!bone.name.Contains("ひざ") || !bone.name.Contains("_J_LegLow01_"))
		{
			return;
		}
		Vector3 localEulerAngles2 = bone.localEulerAngles;
		if (CCDIKSolver.adjust_rot(localEulerAngles2.y) == CCDIKSolver.adjust_rot(localEulerAngles2.z))
		{
			localEulerAngles2.y = (float)CCDIKSolver.adjust_rot(localEulerAngles2.y);
			localEulerAngles2.z = (float)CCDIKSolver.adjust_rot(localEulerAngles2.z);
		}
		if (localEulerAngles2.x > 180f)
		{
			localEulerAngles2.x -= 360f;
		}
		if (localEulerAngles2.x < 0f)
		{
			localEulerAngles2.x = 0f;
		}
		else if (localEulerAngles2.x > 170f)
		{
			localEulerAngles2.x = 170f;
		}
		bone.localRotation = Quaternion.Euler(localEulerAngles2);
	}

	public static int adjust_rot(float n)
	{
		if (Mathf.Abs(n) > Mathf.Abs(180f - n) && Mathf.Abs(360f - n) > Mathf.Abs(180f - n))
		{
			return 180;
		}
		return 0;
	}


}
